summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service/nfc/common/device_manager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service/nfc/common/device_manager.cpp')
-rw-r--r--src/core/hle/service/nfc/common/device_manager.cpp695
1 files changed, 695 insertions, 0 deletions
diff --git a/src/core/hle/service/nfc/common/device_manager.cpp b/src/core/hle/service/nfc/common/device_manager.cpp
new file mode 100644
index 000000000..d5deaaf27
--- /dev/null
+++ b/src/core/hle/service/nfc/common/device_manager.cpp
@@ -0,0 +1,695 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "common/logging/log.h"
+#include "core/core.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/kernel/k_event.h"
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/nfc/common/device.h"
+#include "core/hle/service/nfc/common/device_manager.h"
+#include "core/hle/service/nfc/nfc_result.h"
+#include "core/hle/service/time/clock_types.h"
+
+namespace Service::NFC {
+
+DeviceManager::DeviceManager(Core::System& system_, KernelHelpers::ServiceContext& service_context_)
+ : system{system_}, service_context{service_context_} {
+
+ availability_change_event =
+ service_context.CreateEvent("Nfc:DeviceManager:AvailabilityChangeEvent");
+
+ for (u32 device_index = 0; device_index < devices.size(); device_index++) {
+ devices[device_index] =
+ std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system,
+ service_context, availability_change_event);
+ }
+
+ is_initialized = false;
+}
+
+DeviceManager ::~DeviceManager() {
+ service_context.CloseEvent(availability_change_event);
+}
+
+Result DeviceManager::Initialize() {
+ for (auto& device : devices) {
+ device->Initialize();
+ }
+ is_initialized = true;
+ return ResultSuccess;
+}
+
+Result DeviceManager::Finalize() {
+ for (auto& device : devices) {
+ device->Finalize();
+ }
+ is_initialized = false;
+ return ResultSuccess;
+}
+
+Result DeviceManager::ListDevices(std::vector<u64>& nfp_devices,
+ std::size_t max_allowed_devices) const {
+ for (auto& device : devices) {
+ if (nfp_devices.size() >= max_allowed_devices) {
+ continue;
+ }
+ if (device->GetCurrentState() != DeviceState::Unavailable) {
+ nfp_devices.push_back(device->GetHandle());
+ }
+ }
+
+ if (nfp_devices.empty()) {
+ return ResultDeviceNotFound;
+ }
+
+ return ResultSuccess;
+}
+
+DeviceState DeviceManager::GetDeviceState(u64 device_handle) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ const auto result = GetDeviceFromHandle(device_handle, device, false);
+
+ if (result.IsSuccess()) {
+ return device->GetCurrentState();
+ }
+
+ return DeviceState::Unavailable;
+}
+
+Result DeviceManager::GetNpadId(u64 device_handle, Core::HID::NpadIdType& npad_id) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetNpadId(npad_id);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachAvailabilityChangeEvent() const {
+ return availability_change_event->GetReadableEvent();
+}
+
+Result DeviceManager::StartDetection(u64 device_handle, NfcProtocol tag_protocol) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->StartDetection(tag_protocol);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::StopDetection(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->StopDetection();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetTagInfo(u64 device_handle, TagInfo& tag_info, bool is_mifare) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetTagInfo(tag_info, is_mifare);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachActivateEvent(u64 device_handle) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ GetDeviceFromHandle(device_handle, device, false);
+
+ // TODO: Return proper error code on failure
+ return device->GetActivateEvent();
+}
+
+Kernel::KReadableEvent& DeviceManager::AttachDeactivateEvent(u64 device_handle) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ GetDeviceFromHandle(device_handle, device, false);
+
+ // TODO: Return proper error code on failure
+ return device->GetDeactivateEvent();
+}
+
+Result DeviceManager::ReadMifare(u64 device_handle,
+ std::span<const MifareReadBlockParameter> read_parameters,
+ std::span<MifareReadBlockData> read_data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->ReadMifare(read_parameters, read_data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::WriteMifare(u64 device_handle,
+ std::span<const MifareWriteBlockParameter> write_parameters) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->WriteMifare(write_parameters);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::SendCommandByPassThrough(u64 device_handle,
+ const Time::Clock::TimeSpanType& timeout,
+ std::span<const u8> command_data,
+ std::span<u8> out_data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->SendCommandByPassThrough(timeout, command_data, out_data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Mount(u64 device_handle, NFP::ModelType model_type,
+ NFP::MountTarget mount_target) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Mount(model_type, mount_target);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Unmount(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Unmount();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::OpenApplicationArea(u64 device_handle, u32 access_id) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->OpenApplicationArea(access_id);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetApplicationArea(u64 device_handle, std::span<u8> data) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetApplicationArea(data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::SetApplicationArea(u64 device_handle, std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->SetApplicationArea(data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Flush(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Flush();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Restore(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Restore();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::CreateApplicationArea(u64 device_handle, u32 access_id,
+ std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->CreateApplicationArea(access_id, data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetRegisterInfo(u64 device_handle, NFP::RegisterInfo& register_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetRegisterInfo(register_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetCommonInfo(u64 device_handle, NFP::CommonInfo& common_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetCommonInfo(common_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetModelInfo(u64 device_handle, NFP::ModelInfo& model_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetModelInfo(model_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+u32 DeviceManager::GetApplicationAreaSize() const {
+ return sizeof(NFP::ApplicationArea);
+}
+
+Result DeviceManager::RecreateApplicationArea(u64 device_handle, u32 access_id,
+ std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->RecreateApplicationArea(access_id, data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::Format(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->Format();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetAdminInfo(u64 device_handle, NFP::AdminInfo& admin_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetAdminInfo(admin_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetRegisterInfoPrivate(u64 device_handle,
+ NFP::RegisterInfoPrivate& register_info) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetRegisterInfoPrivate(register_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::SetRegisterInfoPrivate(u64 device_handle,
+ const NFP::RegisterInfoPrivate& register_info) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->SetRegisterInfoPrivate(register_info);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::DeleteRegisterInfo(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->DeleteRegisterInfo();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::DeleteApplicationArea(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->DeleteApplicationArea();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::ExistsApplicationArea(u64 device_handle, bool& has_application_area) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->ExistsApplicationArea(has_application_area);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetAll(u64 device_handle, NFP::NfpData& nfp_data) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->GetAll(nfp_data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::SetAll(u64 device_handle, const NFP::NfpData& nfp_data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->SetAll(nfp_data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::FlushDebug(u64 device_handle) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->FlushDebug();
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::BreakTag(u64 device_handle, NFP::BreakType break_type) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->BreakTag(break_type);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::ReadBackupData(u64 device_handle, std::span<u8> data) const {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->ReadBackupData(data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::WriteBackupData(u64 device_handle, std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->WriteBackupData(data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::WriteNtf(u64 device_handle, NFP::WriteType, std::span<const u8> data) {
+ std::scoped_lock lock{mutex};
+
+ std::shared_ptr<NfcDevice> device = nullptr;
+ auto result = GetDeviceHandle(device_handle, device);
+
+ if (result.IsSuccess()) {
+ result = device->WriteNtf(data);
+ result = VerifyDeviceResult(device, result);
+ }
+
+ return result;
+}
+
+Result DeviceManager::GetDeviceFromHandle(u64 handle, std::shared_ptr<NfcDevice>& nfc_device,
+ bool check_state) const {
+ if (check_state) {
+ const Result is_parameter_set = IsNfcParameterSet();
+ if (is_parameter_set.IsError()) {
+ return is_parameter_set;
+ }
+ const Result is_enabled = IsNfcEnabled();
+ if (is_enabled.IsError()) {
+ return is_enabled;
+ }
+ const Result is_nfc_initialized = IsNfcInitialized();
+ if (is_nfc_initialized.IsError()) {
+ return is_nfc_initialized;
+ }
+ }
+
+ for (auto& device : devices) {
+ if (device->GetHandle() == handle) {
+ nfc_device = device;
+ return ResultSuccess;
+ }
+ }
+
+ return ResultDeviceNotFound;
+}
+
+std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) {
+ for (auto& device : devices) {
+ if (device->GetHandle() == handle) {
+ return device;
+ }
+ }
+ return std::nullopt;
+}
+
+const std::optional<std::shared_ptr<NfcDevice>> DeviceManager::GetNfcDevice(u64 handle) const {
+ for (auto& device : devices) {
+ if (device->GetHandle() == handle) {
+ return device;
+ }
+ }
+ return std::nullopt;
+}
+
+Result DeviceManager::GetDeviceHandle(u64 handle, std::shared_ptr<NfcDevice>& device) const {
+ const auto result = GetDeviceFromHandle(handle, device, true);
+ if (result.IsError()) {
+ return result;
+ }
+ return CheckDeviceState(device);
+}
+
+Result DeviceManager::VerifyDeviceResult(std::shared_ptr<NfcDevice> device,
+ Result operation_result) const {
+ if (operation_result.IsSuccess()) {
+ return operation_result;
+ }
+
+ const Result is_parameter_set = IsNfcParameterSet();
+ if (is_parameter_set.IsError()) {
+ return is_parameter_set;
+ }
+ const Result is_enabled = IsNfcEnabled();
+ if (is_enabled.IsError()) {
+ return is_enabled;
+ }
+ const Result is_nfc_initialized = IsNfcInitialized();
+ if (is_nfc_initialized.IsError()) {
+ return is_nfc_initialized;
+ }
+ const Result device_state = CheckDeviceState(device);
+ if (device_state.IsError()) {
+ return device_state;
+ }
+
+ return operation_result;
+}
+
+Result DeviceManager::CheckDeviceState(std::shared_ptr<NfcDevice> device) const {
+ if (device == nullptr) {
+ return ResultInvalidArgument;
+ }
+
+ return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcEnabled() const {
+ // TODO: This calls nn::settings::detail::GetNfcEnableFlag
+ const bool is_enabled = true;
+ if (!is_enabled) {
+ return ResultNfcDisabled;
+ }
+ return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcParameterSet() const {
+ // TODO: This calls checks against a bool on offset 0x450
+ const bool is_set = true;
+ if (!is_set) {
+ return ResultUnknown76;
+ }
+ return ResultSuccess;
+}
+
+Result DeviceManager::IsNfcInitialized() const {
+ if (!is_initialized) {
+ return ResultNfcNotInitialized;
+ }
+ return ResultSuccess;
+}
+
+} // namespace Service::NFC